import 'dart:async';
import 'dart:io';

import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:web_view_flutter/web_view_flutter.dart';
import 'package:webview_windows/webview_windows.dart' as ww;
import 'webview_controller.dart' as wf;
import 'navigation_delegate.dart' as wf;
import 'webview_widget.dart' as wf;

class WebViewController {
  Function(String url)? onPageFinished;
  Function(String url)? _loadUrl;
  Function(String string)? _loadString;
  Future<String> Function()? _currentUrl;
  Function()? _goBack;
  Function()? _goForward;
  Function()? _dispose;

  String _url = '';
  String _string = '';

  WebViewController({this.onPageFinished, String? url, String? string}) {
    _url = url ?? '';
    _string = string ?? '';
  }

  void loadUrl(String url) {
    if (_loadUrl != null) {
      _loadUrl!.call(url);
    } else {
      _url = url;
    }
  }

  void loadString(String string) {
    if (_loadString != null) {
      _loadString!.call(string);
    } else {
      _string = string;
    }
  }

  void goBack() => _goBack?.call();

  void goForward() => _goForward?.call();

  Future<String> get currentUrl async => await _currentUrl?.call() ?? '';

  void dispose() {
    _dispose?.call();
  }
}

class LklWebView extends StatefulWidget {
  final WebViewController controller;

  final bool interactiveEnable;

  const LklWebView(this.controller, {this.interactiveEnable = true});

  @override
  State<StatefulWidget> createState() => _LklWebViewState();
}

class _LklWebViewState extends State<LklWebView> {
  wf.WebViewController? _otherWebViewController;
  ww.WebviewController? _winWebViewController;

  @override
  void initState() {
    super.initState();
    widget.controller._loadUrl = (url) => _loadUrl(url);
    widget.controller._loadString = (string) => _loadString(string);
    widget.controller._currentUrl = () async => await _currentUrl();
    widget.controller._goBack = () {
      _otherWebViewController?.goBack();
      _winWebViewController?.goBack();
    };
    widget.controller._goForward = () {
      _otherWebViewController?.goForward();
      _winWebViewController?.goForward();
    };
    widget.controller._dispose = () => _winWebViewController?.dispose();
    _initController();
  }

  void _initController() async {
    if (Platform.isWindows) {
      _winWebViewController = ww.WebviewController();
      await _winWebViewController!.initialize();
      setState(() {});
      await _winWebViewController!.setBackgroundColor(Colors.transparent);
      await _winWebViewController!.setPopupWindowPolicy(ww.WebviewPopupWindowPolicy.sameWindow);
      _winWebViewController!.url.listen((event) {
        widget.controller.onPageFinished?.call(event);
      });

      if (widget.controller._url.isNotEmpty) {
        _winWebViewController!.loadUrl(widget.controller._url);
        widget.controller._url = '';
      } else if (widget.controller._string.isNotEmpty) {
        _winWebViewController!.loadStringContent(widget.controller._string);
        widget.controller._string = '';
      }
      return;
    }
    _otherWebViewController = wf.WebViewController();
    await _otherWebViewController?.setJavaScriptMode(JavaScriptMode.unrestricted);
    await _otherWebViewController?.setBackgroundColor(Colors.transparent);
    await _otherWebViewController?.setNavigationDelegate(wf.NavigationDelegate(onPageFinished: (url) {
      widget.controller.onPageFinished?.call(url);
    }));
    if (widget.controller._url.isNotEmpty) {
      _otherWebViewController!.loadRequest(Uri.parse(widget.controller._url));
      widget.controller._url = '';
    } else if (widget.controller._string.isNotEmpty) {
      _otherWebViewController!.loadHtmlString(widget.controller._string);
      widget.controller._string = '';
    }
  }

  void _loadUrl(String url) async {
    if (Platform.isWindows) {
      while(!(_winWebViewController?.value.isInitialized ?? false)) {
        await Future.delayed(const Duration(microseconds: 500));
      }
      if (_winWebViewController?.value.isInitialized ?? false) {
        _winWebViewController?.loadUrl(url);
      }
      return;
    }
    _otherWebViewController?.loadRequest(Uri.parse(url));
  }

  void _loadString(String string) async {
    if (Platform.isWindows) {
      while(!(_winWebViewController?.value.isInitialized ?? false)) {
        await Future.delayed(const Duration(microseconds: 500));
      }
      if (_winWebViewController?.value.isInitialized ?? false) {
        _winWebViewController?.loadStringContent(string);
      }
      return;
    }
    _otherWebViewController?.loadHtmlString(string);
  }

  Future<String> _currentUrl() async {
    return await _otherWebViewController?.currentUrl() ?? await _winWebViewController?.url.last ?? '';
  }

  @override
  Widget build(BuildContext context) {
    Widget body = Center(child: Text('初始化...', style: TextStyle(color: Colors.grey, fontSize: 20)));
    if (Platform.isWindows) {
      if (_winWebViewController?.value.isInitialized ?? false) {
        body = ww.Webview(_winWebViewController!);
      }
    } else {
      if (_otherWebViewController != null) {
        body = wf.WebViewWidget(controller: _otherWebViewController!);
      }
    }
    return widget.interactiveEnable ? body : AbsorbPointer(child: body);
  }

  @override
  void dispose() {
    if (Platform.isWindows) {
      _winWebViewController?.dispose();
    }
    super.dispose();
  }
}
